package com.lc.selector;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;

import org.junit.Before;
import org.junit.Test;

public class SelectorTest {
	Selector selector = null;
	SocketChannel socketChannel = null;

	@Before
	public void before() {
		try {
			selector = Selector.open();
			socketChannel = SocketChannel.open();
			socketChannel.connect(new InetSocketAddress("127.0.0.1", 9999));
			socketChannel.configureBlocking(false);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@SuppressWarnings("rawtypes")
	@Test
	public void selectorTest() throws IOException {
		socketChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE | SelectionKey.OP_CONNECT);
		while (true) {
			int n = selector.select();
			if (n == 0)
				continue;
			Iterator keyIterator = selector.selectedKeys().iterator();
			while (keyIterator.hasNext()) {
				SelectionKey key1 = (SelectionKey) keyIterator.next();
				if (key1.isAcceptable()) {
					System.out.println("服务端接收就绪");
				} else if (key1.isConnectable()) {
					System.out.println("客户端连接接续");
				} else if (key1.isReadable()) {
					System.out.println(key1.hashCode() + "读取就绪");
					SocketChannel socketChannel1 = (SocketChannel) key1.channel();
					ByteBuffer bBuffer = ByteBuffer.allocate(48);
					for (int readSize = socketChannel1.read(bBuffer); readSize != -1; readSize = socketChannel1
							.read(bBuffer)) {
						if (readSize == 0)
							continue;
						bBuffer.flip();
						System.out.println(Charset.forName("UTF-8").decode(bBuffer));
						bBuffer.clear();
					}
					socketChannel1.close();
				} else if (key1.isWritable()) {
					System.out.println(key1.hashCode() + "写入就绪");
				}
				keyIterator.remove();
			}
		}
	}
	
	/**
	 * @throws IOException
	 *             监控server，当client连接时，会新建连接，并监控该channel
	 */
	@Test
	public void socketSelector() throws IOException {
		Selector selector = Selector.open();
		ServerSocketChannel server = ServerSocketChannel.open();
		server.configureBlocking(false);
		server.bind(new InetSocketAddress(9999));
		server.register(selector, SelectionKey.OP_ACCEPT);
		while (true) {
			int i = selector.select();
			if (i != 0) {
				Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
				while (keys.hasNext()) {
					SelectionKey key = keys.next();
					ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
					if (key.isAcceptable()) {
						System.out.println("服务端连接成功");
						Selector connSelector = Selector.open();
						SocketChannel connChannel = serverChannel.accept();
						connChannel.configureBlocking(false);
						connChannel.register(connSelector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
						Thread th = new Thread() {
							@SuppressWarnings("unused")
							public void run() {
								ByteBuffer readBuffer = ByteBuffer.allocate(64);
								ByteBuffer writeBuffer = ByteBuffer.allocate(64);
								while (true) {
									try {
										int i = connSelector.select();
										if (i != 0) {
											Iterator<SelectionKey> keys = connSelector.selectedKeys().iterator();
											while (keys.hasNext()) {
												SelectionKey key = keys.next();
												SocketChannel channel = (SocketChannel) key.channel();
												if (key.isReadable()) {
													System.out.println("服务通道读取就绪");
													int readSize = channel.read(readBuffer);
													while (readSize != -1) {
														if (readSize == 0)
															continue;
														readBuffer.flip();
														System.out.print(Charset.forName("UTF-8").decode(readBuffer));
														readBuffer.clear();
														readSize = channel.read(readBuffer);
													}
												} else if (key.isWritable()) {
													System.out.println("服务通道写入就绪");
												}
											}
										}
									} catch (IOException e) {
										e.printStackTrace();
									}
								}
							}
						};
						th.start();
					}
				}
			}
		}
	}
}
